package com.ruoyi.system.service.impl;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

import com.ruoyi.system.domain.*;
import com.ruoyi.system.mapper.*;
import com.ruoyi.system.service.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.bean.BeanValidators;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.validation.Validator;

import com.ruoyi.system.domain.dto.StatisticsDTO;
import com.ruoyi.system.domain.dto.StatisticsDTO.PositionData;

/**
 * 四级联考体能测评Service业务层处理
 * 
 * @author ruoyi
 * @date 2025-04-02
 */
@Service
public class PhysicalManagementServiceImpl implements IPhysicalManagementService 
{
    private static final Logger log = LoggerFactory.getLogger(PhysicalManagementServiceImpl.class);

    @Autowired
    private PhysicalManagementMapper physicalManagementMapper;
    
    @Autowired
    protected Validator validator;
    
    @Autowired
    private IScoreManagementService scoreManagementService;
    
    @Autowired
    private IDbPhysicalManagementService dbPhysicalManagementService;
    
    @Autowired
    private IResultManagementService resultManagementService;
    @Autowired
    private QualificationManagementMapper qualificationManagementMapper;

    @Autowired
    private DbIdentityManagementMapper dbIdentityManagementMapper;
    @Autowired
    private IdentityManagementMapper identityManagementMapper;

    @Autowired
    private DbQualificationManagementMapper dbQualificationManagementMapper;

    @Autowired
    private IDbQualificationManagementService dbQualificationManagementService;

    /**
     * 查询四级联考体能测评
     * 
     * @param id 四级联考体能测评主键
     * @return 四级联考体能测评
     */
    @Override
    public PhysicalManagement selectPhysicalManagementById(Long id)
    {
        return physicalManagementMapper.selectPhysicalManagementById(id);
    }

    /**
     * 查询四级联考体能测评列表
     * 
     * @param physicalManagement 四级联考体能测评
     * @return 四级联考体能测评
     */
    @Override
    public List<PhysicalManagement> selectPhysicalManagementList(PhysicalManagement physicalManagement)
    {
        return physicalManagementMapper.selectPhysicalManagementList(physicalManagement);
    }

    /**
     * 新增四级联考体能测评
     * 
     * @param physicalManagement 四级联考体能测评
     * @return 结果
     */
    @Override
    public int insertPhysicalManagement(PhysicalManagement physicalManagement)
    {
        return physicalManagementMapper.insertPhysicalManagement(physicalManagement);
    }

    /**
     * 修改四级联考体能测评
     * 
     * @param physicalManagement 四级联考体能测评
     * @return 结果
     */
    @Override
    @Transactional
    public int updatePhysicalManagement(PhysicalManagement physicalManagement)
    {
        // 获取原有数据
        PhysicalManagement originalData = selectPhysicalManagementById(physicalManagement.getId());
        
        // 执行更新操作
        int rows = physicalManagementMapper.updatePhysicalManagement(physicalManagement);
        
        // 如果更新成功，且体能测评结果从非"通过"变为"通过"，则检查是否需要自动流转到终审结果模块
        if (rows > 0 && "通过".equals(physicalManagement.getPhysicalTestResult()) 
            && (originalData == null || !"通过".equals(originalData.getPhysicalTestResult())))
        {
            // 获取更新后的完整数据
            PhysicalManagement updatedData = selectPhysicalManagementById(physicalManagement.getId());
            
            // 检查资格审查和身份验证是否都通过
            if ("通过".equals(updatedData.getQualificationReviewResult()) && 
                "通过".equals(updatedData.getIdentityVerificationResult()))
            {
                log.info("考生{}（身份证号：{}）资格审查、身份验证、体能测评均已通过，自动流转到终审结果模块", 
                         updatedData.getName(), updatedData.getIdCard());
                
                try
                {
                    // 创建只包含当前考生的列表
                    List<PhysicalManagement> qualifiedList = new java.util.ArrayList<>();
                    qualifiedList.add(updatedData);
                    
                    // 设置最终结果为通过
                    updatedData.setFinalResult("通过");
                    physicalManagementMapper.updatePhysicalManagement(updatedData);
                    
                    // 调用终审结果服务，将考生添加到终审结果名单
                    int count = resultManagementService.insertResultListFromPhysical(qualifiedList, "系统自动");
                    log.info("考生{}（身份证号：{}）成功流转到终审结果模块", 
                             updatedData.getName(), updatedData.getIdCard());
                }
                catch (Exception e)
                {
                    log.error("考生流转到终审结果模块失败", e);
                    // 这里不抛出异常，确保即使流转失败，更新操作仍然成功
                }
            }
        }
        
        return rows;
    }

    /**
     * 批量删除四级联考体能测评
     * 
     * @param ids 需要删除的四级联考体能测评主键
     * @return 结果
     */
    @Override
    public int deletePhysicalManagementByIds(Long[] ids)
    {
        return physicalManagementMapper.deletePhysicalManagementByIds(ids);
    }

    /**
     * 删除四级联考体能测评信息
     * 
     * @param id 四级联考体能测评主键
     * @return 结果
     */
    @Override
    public int deletePhysicalManagementById(Long id)
    {
        return physicalManagementMapper.deletePhysicalManagementById(id);
    }

    /**
     * 导入四级联考体能测评数据
     * 
     * @param physicalList 体能测评数据列表
     * @param updateSupport 是否更新支持，如果已存在，是否覆盖
     * @param operName 操作用户
     * @return 结果
     */
    @Override
    @Transactional
    public String importPhysicalData(List<PhysicalManagement> physicalList, boolean updateSupport, String operName)
    {
        if (StringUtils.isNull(physicalList) || physicalList.size() == 0)
        {
            throw new ServiceException("导入数据不能为空！");
        }
        int successNum = 0;
        int failureNum = 0;
        StringBuilder successMsg = new StringBuilder();
        StringBuilder failureMsg = new StringBuilder();
        
        for (PhysicalManagement physical : physicalList)
        {
            try
            {
                // 验证是否存在相同的准考证号或身份证号
                PhysicalManagement existPhysical = new PhysicalManagement();
                if (StringUtils.isNotEmpty(physical.getExamNumber()))
                {
                    existPhysical.setExamNumber(physical.getExamNumber());
                }
                else if (StringUtils.isNotEmpty(physical.getIdCard()))
                {
                    existPhysical.setIdCard(physical.getIdCard());
                }
                else
                {
                    throw new ServiceException("导入数据中准考证号和身份证号不能同时为空");
                }
                
                List<PhysicalManagement> existList = physicalManagementMapper.selectPhysicalManagementList(existPhysical);
                
                if (StringUtils.isNull(existList) || existList.size() == 0)
                {
                    // 如果不存在，执行插入操作
                    physicalManagementMapper.insertPhysicalManagement(physical);
                    successNum++;
                    successMsg.append("<br/>" + successNum + "、准考证号 " + physical.getExamNumber() + " 导入成功");
                }
                else if (updateSupport)
                {
                    // 如果存在且允许更新
                    physical.setId(existList.get(0).getId()); // 设置ID，确保更新正确的记录
                    physicalManagementMapper.updatePhysicalManagement(physical);
                    successNum++;
                    successMsg.append("<br/>" + successNum + "、准考证号 " + physical.getExamNumber() + " 更新成功");
                }
                else
                {
                    failureNum++;
                    failureMsg.append("<br/>" + failureNum + "、准考证号 " + physical.getExamNumber() + " 已存在");
                }
            }
            catch (Exception e)
            {
                failureNum++;
                String msg = "<br/>" + failureNum + "、准考证号 " + physical.getExamNumber() + " 导入失败：";
                failureMsg.append(msg + e.getMessage());
                log.error(msg, e);
            }
        }
        
        if (failureNum > 0)
        {
            failureMsg.insert(0, "很抱歉，导入失败！共 " + failureNum + " 条数据格式不正确，错误如下：");
            throw new ServiceException(failureMsg.toString());
        }
        else
        {
            successMsg.insert(0, "恭喜您，数据已全部导入成功！共 " + successNum + " 条，数据如下：");
        }
        return successMsg.toString();
    }

    /**
     * 从身份验证名单生成并插入体能测评名单
     * 
     * @param identityList 符合条件的身份验证名单数据列表
     * @param operName 操作用户
     * @return 结果
     */
    @Override
    @Transactional
    public int insertPhysicalListFromIdentity(List<IdentityManagement> identityList, String operName)
    {
        if (StringUtils.isNull(identityList) || identityList.size() == 0)
        {
            throw new ServiceException("符合条件的考生数据不能为空！");
        }
        
        int successNum = 0;
        
        // 遍历符合条件的考生，插入体能测评名单
        for (IdentityManagement identity : identityList)
        {
            try
            {
                // 只有身份验证结果为"通过"的考生才能进入体能测评环节
                if ("通过".equals(identity.getIdentityVerificationResult()))
                {
                    // 检查是否已经存在相同准考证号的记录
                    PhysicalManagement existCheck = new PhysicalManagement();
                    existCheck.setExamNumber(identity.getExamNumber());
                    List<PhysicalManagement> existList = physicalManagementMapper.selectPhysicalManagementList(existCheck);
                    
                    // 如果不存在，则插入新记录
                    if (StringUtils.isNull(existList) || existList.size() == 0)
                    {
                        // 创建体能测评名单对象
                        PhysicalManagement physical = new PhysicalManagement();
                        
                        // 复制考生信息
                        physical.setCandidateId(identity.getCandidateId());
                        physical.setName(identity.getName());
                        physical.setGender(identity.getGender());
                        physical.setIdCard(identity.getIdCard());
                        physical.setExamNumber(identity.getExamNumber());
                        physical.setAdministrativeAptitudeScore(identity.getAdministrativeAptitudeScore());
                        physical.setEssayScore(identity.getEssayScore());
                        physical.setProfessionalSubjectScore(identity.getProfessionalSubjectScore());
                        physical.setTotalScore(identity.getTotalScore());
                        physical.setProfessionalSkillTestScore(identity.getProfessionalSkillTestScore());
                        physical.setAppliedUnit(identity.getAppliedUnit());
                        physical.setAppliedPosition(identity.getAppliedPosition());
                        physical.setRecruitmentNumber(identity.getRecruitmentNumber());
                        physical.setInterviewRatio(identity.getInterviewRatio());
                        physical.setRanking(identity.getRanking());
                        physical.setGraduationSchool(identity.getGraduationSchool());
                        physical.setHasProfessionalSkillTest(identity.getHasProfessionalSkillTest());
                        physical.setPositionCategory(identity.getPositionCategory());
                        physical.setIsAlternate(identity.getIsAlternate());
                        physical.setQualificationReviewResult(identity.getQualificationReviewResult());
                        physical.setIdentityVerificationResult(identity.getIdentityVerificationResult());
//                        physical.setPhysicalTestResult("待测评");  // 默认为待测评
//                        physical.setFinalResult("待确认");  // 默认为待确认
                        
                        // 执行插入操作
                        physicalManagementMapper.insertPhysicalManagement(physical);
                        successNum++;
                        log.info("考生[" + identity.getName() + ", 准考证号:" + identity.getExamNumber() 
                            + "]身份验证通过，成功流转到体能测评环节");
                    }
                }
            }
            catch (Exception e)
            {
                log.error("插入体能测评名单失败，准考证号：" + identity.getExamNumber(), e);
            }
        }
        
        return successNum;
    }

    /**
     * 生成递补体能测试名单
     * 找出不合格考生职位，按照相同报考单位报考职位从成绩合格名单中递补考生
     * 
     * @param operName 操作用户
     * @return 递补人数
     */
    @Override
    @Transactional
    public int generateDbPhysicalList(String operName) {
        // 1. 统计各职位体能测试未通过人数
        Map<String, Integer> positionFailureCount = new HashMap<>();


        // 获取资格审查不通过的考生职位
        QualificationManagement failedQualification = new QualificationManagement();
        failedQualification.setQualificationReviewResult("未通过");
        List<QualificationManagement> failedQualificationList = qualificationManagementMapper.selectQualificationManagementList(failedQualification);
// 获取身份验证的考生
        IdentityManagement failedIdentityall = new IdentityManagement();
        List<IdentityManagement> failedListall = identityManagementMapper.selectIdentityManagementList(failedIdentityall);
        // 获取递补资格审查的考生
        DbQualificationManagement failedDBQualificationall = new DbQualificationManagement();
        List<DbQualificationManagement> failedDBQualificationListall = dbQualificationManagementMapper.selectDbQualificationManagementList(failedDBQualificationall);

        // 获取递补身份验证的考生
        DbIdentityManagement failedDBIdentityall = new DbIdentityManagement();
        List<DbIdentityManagement> failedDBIdentityListall = dbIdentityManagementMapper.selectDbIdentityManagementList(failedDBIdentityall);

        // 获取体能测试未通过的考生
        PhysicalManagement failedCriteria = new PhysicalManagement();
        failedCriteria.setPhysicalTestResult("未通过");
        List<PhysicalManagement> failedList = physicalManagementMapper.selectPhysicalManagementList(failedCriteria);

        PhysicalManagement failedCriteriaall = new PhysicalManagement();
        List<PhysicalManagement> failedCriteriaList = physicalManagementMapper.selectPhysicalManagementList(failedCriteriaall);

        // 统计每个职位的未通过数量
        failedList.forEach(item -> {
            String positionKey = item.getAppliedUnit() + "_" + item.getAppliedPosition();
            positionFailureCount.put(positionKey, positionFailureCount.getOrDefault(positionKey, 0) + 1);
        });

        if (positionFailureCount.isEmpty()) {
            log.info("没有体能测试未通过的职位，无需递补");
            return 0;
        }

        // 2. 获取所有成绩合格考生
        List<ScoreManagement> allScores = scoreManagementService.selectScoreManagementList(new ScoreManagement());

        // 3. 构建排除条件集合（已存在于体能测评表的考生）
        Set<String> excludeQualificationfiers = failedQualificationList.stream()
                .map(i -> i.getExamNumber() + "_" + i.getIdCard())
                .collect(Collectors.toSet());
        Set<String> excludeIdentifiers = failedListall.stream()
                .map(i -> i.getExamNumber() + "_" + i.getIdCard())
                .collect(Collectors.toSet());
        Set<String> excludeDBIdentifiers = failedDBIdentityListall.stream()
                .map(i -> i.getExamNumber() + "_" + i.getIdCard())
                .collect(Collectors.toSet());
        Set<String> excludeDBQualifications = failedDBQualificationListall.stream()
                .map(i -> i.getExamNumber() + "_" + i.getIdCard())
                .collect(Collectors.toSet());


        Set<String> excludeCriteriaall = failedCriteriaList.stream()
                .map(i -> i.getExamNumber() + "_" + i.getIdCard())
                .collect(Collectors.toSet());
        excludeCriteriaall.addAll(excludeQualificationfiers);
        excludeCriteriaall.addAll(excludeIdentifiers);
        excludeCriteriaall.addAll(excludeDBIdentifiers);
        excludeCriteriaall.addAll(excludeDBQualifications);




        // 4. 过滤有效考生
        List<ScoreManagement> validScores = allScores.stream()
                .filter(score -> !excludeCriteriaall.contains(score.getExamNumber() + "_" + score.getIdCard()))
                .collect(Collectors.toList());

        // 5. 按职位分组处理
        Map<String, List<ScoreManagement>> grouped = validScores.stream()
                .collect(Collectors.groupingBy(s -> s.getAppliedUnit() + "_" + s.getAppliedPosition()));

        List<ScoreManagement> finalCandidates = new ArrayList<>();

        for (Map.Entry<String, List<ScoreManagement>> entry : grouped.entrySet()) {
            String positionKey = entry.getKey();
            List<ScoreManagement> group = entry.getValue();

            // 只处理存在未通过考生的职位
            if (!positionFailureCount.containsKey(positionKey) || group.isEmpty()) continue;

            // 获取该职位需要递补的数量
            int required = positionFailureCount.get(positionKey);

            // 排序逻辑（降序）
            group.sort((a, b) -> {
                boolean hasSkillTest = "是".equals(a.getHasProfessionalSkillTest());
                if (hasSkillTest) {
                    return b.getProfessionalSkillTestScore().compareTo(a.getProfessionalSkillTestScore());
                } else {
                    return b.getTotalScore().compareTo(a.getTotalScore());
                }
            });

            // 计算实际可递补人数
            int actualCount = Math.min(required, group.size());
            if (actualCount == 0) continue;

            // 处理同分考生
            boolean hasSkillTest = "是".equals(group.get(0).getHasProfessionalSkillTest());
            BigDecimal baseScore = hasSkillTest ?
                    group.get(actualCount-1).getProfessionalSkillTestScore() :
                    group.get(actualCount-1).getTotalScore();

            for (int i = actualCount; i < group.size(); i++) {
                BigDecimal current = hasSkillTest ?
                        group.get(i).getProfessionalSkillTestScore() :
                        group.get(i).getTotalScore();

                if (current.compareTo(baseScore) == 0) {
                    actualCount++;
                } else {
                    break;
                }
            }

            // 添加最终递补名单
            finalCandidates.addAll(group.subList(0, Math.min(actualCount, group.size())));
        }

        // 6. 插入递补数据（存在校验）
       /* return dbPhysicalManagementService.insertDbPhysicalListFromScore(
                finalCandidates.stream()
                        .filter(score -> StringUtils.isNotEmpty(score.getIdCard()))
                        .collect(Collectors.toList()),
                operName
        );*/

        // 6. 插入递补数据（存在校验）
        return dbQualificationManagementService.insertDbQualificationListFromScore(
                finalCandidates.stream()
                        .filter(score -> StringUtils.isNotEmpty(score.getIdCard()))
                        .collect(Collectors.toList()),
                operName
        );
    }

    /**
     * 获取四级联考体能测评统计数据
     * 
     * @return 统计数据
     */
    @Override
    public StatisticsDTO getPhysicalStatistics()
    {
        // 创建返回对象
        StatisticsDTO statisticsDTO = new StatisticsDTO();
        
        // 查询所有体能测评数据
        List<PhysicalManagement> physicalList = physicalManagementMapper.selectPhysicalManagementList(new PhysicalManagement());
        
        // 总数
        int total = physicalList.size();
        statisticsDTO.setTotal(total);
        
        // 通过和未通过数量
        int passed = 0;
        // 职位分布统计
        Map<String, Integer> positionMap = new HashMap<>();
        
        for (PhysicalManagement physical : physicalList)
        {
            // 统计通过人数
            if ("通过".equals(physical.getPhysicalTestResult()))
            {
                passed++;
            }
            
            // 统计职位分布
            String position = physical.getAppliedPosition();
            if (position != null && !position.isEmpty())
            {
                positionMap.put(position, positionMap.getOrDefault(position, 0) + 1);
            }
        }
        
        statisticsDTO.setPassed(passed);
        statisticsDTO.setFailed(total - passed);
        
        // 转换职位分布数据为前端所需格式
        List<PositionData> positionDataList = new ArrayList<>();
        for (Map.Entry<String, Integer> entry : positionMap.entrySet())
        {
            positionDataList.add(new PositionData(entry.getKey(), entry.getValue()));
        }
        statisticsDTO.setPositionData(positionDataList);
        
        return statisticsDTO;
    }
}
